﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace CL2036.Sock
{
    internal class UDPClient
    {
        /// <summary>
        /// 本地绑定端口
        /// </summary>
        private int UdpBindPort;

        private UdpClient Client;
        /// <summary>
        /// 远程通信点
        /// </summary>
        private IPEndPoint Point = new IPEndPoint(IPAddress.Parse("193.168.18.1"), 10003);
        /// <summary>
        /// 通信参数
        /// </summary>
        private string m_Setting = "1200,e,8,1";

        private bool m_IsInit = false;

        private long m_TimeOut = 1000;

        private long m_FrameTimeOut = 500;

        public long TimeOut
        {
            set { m_TimeOut = value; }
        }

        public long FrameTimeOut
        {
            set { m_FrameTimeOut = 500; }
        }

        /// <summary>
        /// 是否初始化
        /// </summary>
        public bool IsInit
        {
            get { return m_IsInit; }
        }

        /// <summary>
        /// 初始化通信模块
        /// </summary>
        /// <param name="Setting">通信参数（1200,e,8,1）</param>
        /// <param name="IP">IP地址</param>
        /// <param name="BindPort">本地绑定端口</param>
        /// <param name="BindSetPort">本地绑定设置端口</param>
        /// <param name="RemotePort">远程端口</param>
        public void Init(string Setting, string IP, int BindPort, int BindSetPort, int RemotePort)
        {
            m_Setting = Setting;

            Point.Address = IPAddress.Parse(IP);

            Point.Port = RemotePort;

            UdpBindPort = BindPort;

            byte[] SendArr = ASCIIEncoding.ASCII.GetBytes(string.Format("init {0}", m_Setting.Replace(',', ' ')));

            m_IsInit = SendData(BindSetPort, ref  SendArr, false);           //发送初始化参数

        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="Port">端口</param>
        /// <param name="vData">发送的二进制数据</param>
        /// <param name="IsReturn">是否需要返回</param>
        /// <returns></returns>
        private bool SendData(int Port, ref Byte[] vData, bool IsReturn)
        {
            Client = new UdpClient(Port);

            try
            {
                Client.Connect(Point);
            }
            catch { return false; }

            Client.Send(vData, vData.Length);

            if (!IsReturn)
            {
                int i = 0;

                while (i < 10)
                {
                    System.Threading.Thread.Sleep(20);
                    i++;
                }
                Client.Close();
                return true;
            }

            byte[] BytReceived = new byte[0];

            List<byte> RevItems = new List<byte>();     //接收的数据集合

            DateTime Dt;            //等待时间变量

            Dt = DateTime.Now;

            while (TimeSub(DateTime.Now, Dt) < m_TimeOut)
            {
                try
                {
                    if (Client.Available > 0) break;
                }
                catch
                {
                    Client.Close();
                    return false;
                }
            }

            if (Client.Available==0)
            {
                vData = new byte[0];
                Client.Close();
                return false;
            }
            else
            {
                Dt = DateTime.Now;

                while (TimeSub(DateTime.Now, Dt) < m_FrameTimeOut)         //没一个包块延时200毫秒检测是否存在断包的情况
                {
                    if (Client.Available > 0)
                    {
                        RevItems.AddRange(Client.Receive(ref Point));
                        Dt = DateTime.Now;
                    }
                    System.Threading.Thread.Sleep((int)m_FrameTimeOut / 10);
                }

                vData = RevItems.ToArray();
            }

            Client.Close();
            return true;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="vData">发送的二进制数据</param>
        /// <param name="IsReturn">是否需要返回</param>
        /// <returns></returns>
        public bool SendData(ref byte[] vData, bool IsReturn)
        {
            if (!m_IsInit) return false;
            return SendData(UdpBindPort, ref vData, IsReturn);
        }

        private long TimeSub(DateTime Time1, DateTime Time2)
        {
            TimeSpan tsSub = Time1.Subtract(Time2);
            return tsSub.Hours * 60 * 60 * 1000 + tsSub.Minutes * 60 * 1000 + tsSub.Seconds * 1000 + tsSub.Milliseconds;
        }

    }
}
